/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common_components/tests/test_helper.h"
#include "common_components/mutator/mutator.h"
#include "common_components/mutator/mutator.cpp"
#include "common_components/base_runtime/base_runtime.cpp"
#include "common_interfaces/objects/base_object.h"

using namespace common;

namespace common::test {
class TestMutator : public Mutator {
public:
    using Mutator::VisitRawObjects;
};
class MutatorTest : public BaseTestWithScope {
protected:
    void SetUp() override {}
    void TearDown() override {}
    static void SetUpTestCase()
    {
        BaseRuntime::GetInstance()->Init();
    }
    static void TearDownTestCase() {}
};

HWTEST_F_L0(MutatorTest, GetThreadLocalData_Test1)
{
    ThreadLocalData *ret = GetThreadLocalData();
    ASSERT_TRUE(ret != nullptr);
}

HWTEST_F_L0(MutatorTest, TransitionGCPhase_Test1)
{
    MutatorBase *mutatorBase = new MutatorBase();
    mutatorBase->Init();
    bool ret = mutatorBase->TransitionGCPhase(false);
    EXPECT_TRUE(ret == true);

    MutatorBase::SuspensionType  flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE;
    mutatorBase->SetSuspensionFlag(flag);

    ret = mutatorBase->TransitionGCPhase(false);
    EXPECT_TRUE(ret == true);

    ret = mutatorBase->TransitionGCPhase(true);
    EXPECT_TRUE(ret == true);
    ret = mutatorBase->TransitionGCPhase(false);
    EXPECT_TRUE(ret == true);
    delete mutatorBase;
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test1)
{
    MutatorBase *mutatorBase = new MutatorBase();
    mutatorBase->Init();
    MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_STW;
    mutatorBase->SetSuspensionFlag(flag);
    flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE;
    mutatorBase->SetSuspensionFlag(flag);
    mutatorBase->HandleSuspensionRequest();
    EXPECT_FALSE(mutatorBase->InSaferegion());
    EXPECT_TRUE(mutatorBase->FinishedTransition());
    delete mutatorBase;
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test2)
{
    MutatorBase *mutatorBase = new MutatorBase();
    mutatorBase->Init();
    MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_CPU_PROFILE;
    mutatorBase->SetSuspensionFlag(flag);
    mutatorBase->SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE);
    std::thread t([&]() {
        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
        mutatorBase->ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE);
    });
    mutatorBase->HandleSuspensionRequest();
    t.join();
    EXPECT_FALSE(mutatorBase->InSaferegion());
    EXPECT_TRUE(mutatorBase->FinishedCpuProfile());
    delete mutatorBase;
}

HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test3)
{
    MutatorBase *mutatorBase = new MutatorBase();
    mutatorBase->Init();
    mutatorBase->SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_STW);
    mutatorBase->SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE);
    mutatorBase->SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE);
    std::thread t([&]() {
        std::this_thread::sleep_for(std::chrono::nanoseconds(1));
        mutatorBase->ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE);
    });
    mutatorBase->HandleSuspensionRequest();
    t.join();
    EXPECT_FALSE(mutatorBase->InSaferegion());
    EXPECT_TRUE(mutatorBase->FinishedCpuProfile());
    delete mutatorBase;
}

HWTEST_F_L0(MutatorTest, HandleGCPhase_SatbNodeNotNull)
{
    Mutator* mutator = MutatorManager::Instance().CreateRuntimeMutator(ThreadType::GC_THREAD);
    HeapAddress addr = common::HeapManager::Allocate(sizeof(BaseObject), AllocType::MOVEABLE_OBJECT, true);
    BaseObject *mockObj = reinterpret_cast<BaseObject*>(addr);
    new (mockObj) BaseObject();
    mutator->RememberObjectInSatbBuffer(mockObj);
    EXPECT_NE(mutator->GetSatbBufferNode(), nullptr);
    MutatorBase* base = static_cast<MutatorBase*>(mutator->GetMutatorBasePtr());
    base->HandleGCPhase(GCPhase::GC_PHASE_REMARK_SATB);
    EXPECT_EQ(mutator->GetSatbBufferNode(), nullptr);
    MutatorManager::Instance().DestroyRuntimeMutator(ThreadType::GC_THREAD);
}
}  // namespace common::test
